package com.cmc6.area.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cmc6.area.mapper.AreaMapper;
import com.cmc6.area.model.dto.AreaInsertOrUpdateDTO;
import com.cmc6.area.model.dto.AreaPageDTO;
import com.cmc6.area.model.entity.AreaDO;
import com.cmc6.area.model.entity.AreaRefDeptDO;
import com.cmc6.area.model.vo.AreaInfoByIdVO;
import com.cmc6.area.service.AreaRefDeptService;
import com.cmc6.area.service.AreaService;
import com.cmc6.common.exception.BaseBizCodeEnum;
import com.cmc6.common.model.dto.AddOrderNoDTO;
import com.cmc6.common.model.dto.NotEmptyIdSet;
import com.cmc6.common.model.dto.NotNullId;
import com.cmc6.common.model.entity.BaseEntityFour;
import com.cmc6.common.model.entity.BaseEntityThree;
import com.cmc6.common.model.entity.BaseEntityTwo;
import com.cmc6.common.util.ApiResult;
import com.cmc6.common.util.MyEntityUtil;
import com.cmc6.common.util.MyTreeUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class AreaServiceImpl extends ServiceImpl<AreaMapper, AreaDO> implements AreaService {

    @Resource
    AreaRefDeptService areaRefDeptService;

    /**
     * 新增/修改 区域
     */
    @Override
    @Transactional
    public String insertOrUpdate(AreaInsertOrUpdateDTO dto) {

        if (dto.getId() != null && dto.getId().equals(dto.getParentId())) {
            ApiResult.error(BaseBizCodeEnum.PARENT_ID_CANNOT_BE_EQUAL_TO_ID);
        }

        // 相同父节点下：区域名（不能重复）
        Long count = lambdaQuery().eq(AreaDO::getName, dto.getName())
            .eq(BaseEntityFour::getParentId, MyEntityUtil.getNullParentId(dto.getParentId()))
            .ne(dto.getId() != null, BaseEntityTwo::getId, dto.getId()).count();
        if (count != 0) {
            ApiResult.error("操作失败：相同父节点下，区域名不能重复");
        }

        AreaDO areaDO = new AreaDO();
        areaDO.setName(dto.getName());
        areaDO.setParentId(MyEntityUtil.getNullParentId(dto.getParentId()));
        areaDO.setEnableFlag(dto.isEnableFlag());
        areaDO.setId(dto.getId());
        areaDO.setOrderNo(dto.getOrderNo());
        areaDO.setRemark(MyEntityUtil.getNotNullStr(dto.getRemark()));

        if (dto.getId() != null) {
            // 先删除子表数据
            areaRefDeptService.removeById(dto.getId());
        }

        saveOrUpdate(areaDO);

        // 再插入子表数据
        if (CollUtil.isNotEmpty(dto.getDeptIdSet())) {
            List<AreaRefDeptDO> insertList = new ArrayList<>();
            for (Long item : dto.getDeptIdSet()) {
                AreaRefDeptDO areaRefDeptDO = new AreaRefDeptDO();
                areaRefDeptDO.setAreaId(areaDO.getId());
                areaRefDeptDO.setDeptId(item);
                insertList.add(areaRefDeptDO);
            }
            areaRefDeptService.saveBatch(insertList);
        }

        return BaseBizCodeEnum.API_RESULT_OK.getMsg();
    }

    /**
     * 分页排序查询：区域
     */
    @Override
    public Page<AreaDO> myPage(AreaPageDTO dto) {
        return myPageRes(dto);
    }

    /**
     * 分页排序查询：区域-返回值
     */
    private Page<AreaDO> myPageRes(AreaPageDTO dto) {

        return lambdaQuery().like(StrUtil.isNotBlank(dto.getName()), AreaDO::getName, dto.getName())
            .like(StrUtil.isNotBlank(dto.getRemark()), BaseEntityThree::getRemark, dto.getRemark())
            .eq(dto.getId() != null, BaseEntityTwo::getId, dto.getId())
            .eq(dto.getEnableFlag() != null, BaseEntityThree::getEnableFlag, dto.getEnableFlag()).page(dto.getPage());
    }

    /**
     * 查询区域（树结构）
     */
    @Override
    public List<AreaDO> tree(AreaPageDTO dto) {

        List<AreaDO> resultList = new ArrayList<>(); // 本接口返回值

        // 根据条件进行筛选，得到符合条件的数据，然后再逆向生成整棵树，并返回这个树结构
        dto.setPageSize(-1); // 不分页
        List<AreaDO> dbList = myPageRes(dto).getRecords();

        if (dbList.size() == 0) {
            return resultList;
        }

        // 查询出所有的菜单
        List<AreaDO> allList = list();

        if (allList.size() == 0) {
            return resultList;
        }

        return MyTreeUtil.getFullTreeByDeepNode(dbList, allList);
    }

    /**
     * 删除区域
     */
    @Override
    @Transactional
    public String deleteByIdSet(NotEmptyIdSet notEmptyIdSet) {

        // 如果存在下级，则无法删除
        Long selectCount = lambdaQuery().in(BaseEntityFour::getParentId, notEmptyIdSet.getIdSet()).count();
        if (selectCount != 0) {
            ApiResult.error(BaseBizCodeEnum.PLEASE_DELETE_THE_CHILD_NODE_FIRST);
        }

        // 移除子表数据
        areaRefDeptService.lambdaUpdate().in(AreaRefDeptDO::getAreaId, notEmptyIdSet.getIdSet()).remove();

        removeByIds(notEmptyIdSet.getIdSet());

        return BaseBizCodeEnum.API_RESULT_OK.getMsg();
    }

    /**
     * 通过主键id，查看详情
     */
    @Override
    public AreaInfoByIdVO infoById(NotNullId notNullId) {

        AreaDO areaDO = getById(notNullId.getId());
        if (areaDO == null) {
            return null;
        }

        // 封装绑定的部门 idSet
        List<AreaRefDeptDO> areaRefDeptDOList = areaRefDeptService.lambdaQuery().eq(AreaRefDeptDO::getAreaId, notNullId.getId())
            .select(AreaRefDeptDO::getDeptId).list();

        Set<Long> deptIdSet = areaRefDeptDOList.stream().map(AreaRefDeptDO::getDeptId).collect(Collectors.toSet());

        AreaInfoByIdVO resVO = BeanUtil.copyProperties(areaDO, AreaInfoByIdVO.class); // 本接口返回值
        resVO.setDeptIdSet(deptIdSet);

        return resVO;
    }

    /**
     * 通过主键 idSet，加减排序号
     */
    @Override
    @Transactional
    public String addOrderNo(AddOrderNoDTO dto) {
        if (dto.getNumber() == 0) {
            return BaseBizCodeEnum.API_RESULT_OK.getMsg();
        }

        List<AreaDO> listByIds = listByIds(dto.getIdSet());

        for (AreaDO item : listByIds) {
            item.setOrderNo(item.getOrderNo() + dto.getNumber());
        }

        updateBatchById(listByIds);

        return BaseBizCodeEnum.API_RESULT_OK.getMsg();
    }
}




